<!-- components/ThumbnailList/ThumbnailList.vue -->
<template>
  <ul
      class="thumbnail-list"
      :style="{
      gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
      gap: typeof gutter === 'number' ? `${gutter}px` : gutter
    }"
  >
    <li
        v-for="(item, index) in items"
        :key="item[itemKey]"
        class="thumbnail-item"
        :class="{
        'selected': index === selectedIndex,
        'disabled': disabledIndexes.includes(index)
      }"
        :style="{
        width: typeof thumbnailWidth === 'number' ? `${thumbnailWidth}px` : thumbnailWidth,
        height: typeof thumbnailHeight === 'number' ? `${thumbnailHeight}px` : thumbnailHeight
      }"
        @click="handleClick(item, index)"
        @keydown="handleKeyDown($event, index)"
        tabindex="0"
    >
      <!-- 自定义插槽 -->
      <slot v-if="$slots.default" :item="item" :index="index"></slot>
      <div v-else class="thumbnail-content">
        <div class="image-wrapper">
          <img
              :src="loadingPlaceholder"
              :data-src="item.src"
              :alt="item.title"
              class="thumbnail-image"
              @load="handleImageLoad(item, index)"
              @error="handleImageError(item, index)"
              ref="imageRefs"
          />
        </div>
        <div v-if="item.title" class="thumbnail-title">{{ item.title }}</div>
        <div v-if="item.description" class="thumbnail-description">{{ item.description }}</div>
      </div>
    </li>
  </ul>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'

const props = defineProps({
  items: {
    type: Array,
    required: true
  },
  itemKey: {
    type: String,
    default: 'id'
  },
  columns: {
    type: Number,
    default: 3
  },
  gutter: {
    type: [Number, String],
    default: 10
  },
  thumbnailWidth: {
    type: [Number, String],
    default: 200
  },
  thumbnailHeight: {
    type: [Number, String],
    default: 150
  },
  loadingPlaceholder: String,
  selectedIndex: {
    type: Number,
    default: -1
  },
  disabledIndexes: {
    type: Array,
    default: () => []
  }
})

const emit = defineEmits(['click', 'load', 'error', 'select'])

const imageRefs = ref([])
let observer = null

// 懒加载处理
onMounted(() => {
  if ('IntersectionObserver' in window) {
    observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const img = entry.target
          img.src = img.dataset.src
          observer.unobserve(img)
        }
      })
    })

    imageRefs.value.forEach(img => observer.observe(img))
  } else {
    // 浏览器不支持时直接加载所有图片
    imageRefs.value.forEach(img => {
      img.src = img.dataset.src
    })
  }
})

onBeforeUnmount(() => {
  if (observer) observer.disconnect()
})

const handleClick = (item, index) => {
  if (props.disabledIndexes.includes(index)) return

  emit('click', { item, index })
  emit('select', { item, index })
}

const handleKeyDown = (e, index) => {
  if (props.disabledIndexes.includes(index)) return

  const itemsCount = props.items.length
  switch(e.key) {
    case 'ArrowRight':
      focusItem((index + 1) % itemsCount)
      break
    case 'ArrowLeft':
      focusItem((index - 1 + itemsCount) % itemsCount)
      break
    case 'Enter':
      handleClick(props.items[index], index)
      break
  }
}

const focusItem = (index) => {
  const items = document.querySelectorAll('.thumbnail-item')
  if (items[index]) items[index].focus()
}

const handleImageLoad = (item, index) => {
  emit('load', { item, index })
}

const handleImageError = (item, index) => {
  emit('error', { item, index })
}
</script>

<style scoped>
.thumbnail-list {
  display: grid;
  list-style: none;
  padding: 0;
  margin: 0;
}

.thumbnail-item {
  position: relative;
  cursor: pointer;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
  overflow: hidden;
  background: #f5f5f5;
}

.thumbnail-item:hover {
  transform: translateY(-5px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.thumbnail-item.selected {
  outline: 2px solid #2196f3;
  outline-offset: 2px;
}

.thumbnail-item.disabled {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

.image-wrapper {
  position: relative;
  width: 100%;
  height: 80%;
  overflow: hidden;
}

.thumbnail-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity 0.3s ease;
}

.thumbnail-image[data-src] {
  opacity: 0;
}

.thumbnail-image.loaded {
  opacity: 1;
}

.thumbnail-title {
  padding: 8px;
  font-weight: bold;
  text-align: center;
}

.thumbnail-description {
  padding: 0 8px 8px;
  font-size: 0.9em;
  text-align: center;
  color: #666;
}

@media (max-width: 768px) {
  .thumbnail-list {
    grid-template-columns: repeat(2, 1fr) !important;
  }
}

@media (max-width: 480px) {
  .thumbnail-list {
    grid-template-columns: 1fr !important;
  }
}
</style>